#include "proxy/conn/tcpconn.h"

namespace proxy{

  TcpConn::TcpConn(boost::asio::io_service& io_service, CallbackConnect call_back)
    :io_service_(io_service),
    SignalConnectResult(call_back),
    resolver_socket_(io_service),
    connect_(new boost::asio::ip::tcp::socket(io_service)){

  }

  bool TcpConn::Start(const std::string domain, std::string port){
    try{
      boost::asio::ip::tcp::resolver::query query(domain, port);
      resolver_socket_.async_resolve(query,
        boost::bind(&TcpConn::HandleResolve, shared_from_this(),
        boost::asio::placeholders::error,
        boost::asio::placeholders::iterator));
    }
    catch (std::exception &e){
      DLOG(ERROR) << e.what();
      return false;
    }
    return true;
  }

  void TcpConn::HandleResolve(const boost::system::error_code& err,
    boost::asio::ip::tcp::resolver::iterator endpoint_iterator){
    if (err && endpoint_iterator == end_){
      DLOG(ERROR) << err.message();
      SignalConnectResult(socket_ptr(), err);
      return;
    }
    ConnectServer(endpoint_iterator);
  }

  void TcpConn::ConnectServer(
    boost::asio::ip::tcp::resolver::iterator endpoint_iterator){
    boost::asio::ip::tcp::endpoint server_addr = *endpoint_iterator;
    connect_->async_connect(server_addr,
      boost::bind(&TcpConn::HandleConnect, shared_from_this(),
      boost::asio::placeholders::error, ++endpoint_iterator));
  };

  void TcpConn::HandleConnect(const boost::system::error_code& err,
    boost::asio::ip::tcp::resolver::iterator endpoint_iterator){
    if (err && endpoint_iterator == end_){
      SignalConnectResult(socket_ptr(), err);
      return;
    }
    if (err){
      DLOG(WARNING) << "Next Endpoint " << err.message();
      // Connect to the next endpoint
      ConnectServer(endpoint_iterator);
    }
    else{
      SignalConnectResult(connect_, err);
    }

  }


}